<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <link rel="shortcut icon" type="image/x-icon" href="../favicon.ico"/>
    <title>语法指南 jetbrick-template</title>

    <link href="../assets/css/application.min.css" rel="stylesheet" type="text/css"/>

    <!--[if lt IE 9]><script src="../assets/js/html5shiv.js"></script><![endif]-->
    <script type="text/javascript" src="../assets/js/application.min.js"></script>
</head>

<body>
<a href="https://github.com/subchen/jetbrick-template/" target="_blank">
    <img src="../assets/images/forkme_right_orange.png" alt="Fork me on GitHub" class="fork-me-on-github">
</a>

<div class="jb-topbar">
    <div class="container">
        <a href="http://subchen.github.io/"><img src="../assets/images/logo-mini.png"/></a>
        <!--
        <ul class="menubar">
            <li><a href="">commons</a></li>
            <li><a href="">webmvc</a></li>
            <li><a href="">template</a></li>
            <li><a href="">orm</a></li>
            <li><a href="">widget</a></li>
            <li><a href="">javadoc-chm</a></li>
        </ul>
        -->
        <div class="pull-right" style="color:#fff;line-height:40px;font-size:16px;padding-right:20px">QQ 交流圈：310491655</div>
    </div>
</div>

<div class="jb-banner">
    <div class="container">
        <a href="http://subchen.github.io/jetbrick-template/index.html">
            <img src="../assets/images/jetbrick-template-logo.png" class="pull-left" />
        </a>
        <ul class="description">
            <li>1. 全新一代 Java 模板引擎</li>
            <li>2. 具有高性能、高扩展性</li>
            <li>3. 完美替代 JSP, Velocity 等引擎模板</li>
        </ul>
        <a href="download/jetbrick-template-1.2.3.zip" class="download-button">
            <img src="../assets/images/download.png"/>
            <span>jetbrick-template-1.2.3.zip<br/>2014-03-10</span>
        </a>
    </div>
</div>

<div class="container">
    <div class="jb-section">
        <ul class="tabs">
            <li><a href="overview.html">简介</a></li>
            <li><a href="download.html">下载</a></li>
            <li><a href="userguide.html">开发指南</a></li>
            <li><a href="config.html">配置指南</a></li>
            <li><a href="syntax.html" class="selected">语法指南</a></li>
            <li><a href="integrate.html">Web 框架集成</a></li>
            <!--
            <li><a href="example.html">例子</a></li>
            -->
            <li><a href="faq.html">FAQ</a></li>
            <li><a href="about.html">关于</a></li>
        </ul>
    </div>
</div>

<div class="container">
    <div class="announcement">
        <a href="download.html#version">2014-03-10：jetbrick-template-1.2.3 正式版已发布，欢迎下载。</a>
    </div>
</div>

<div class="container">

    <style type="text/css">
        .affix-top {
          float: left;
          margin-top: 20px;
        }
        .affix {
          position: left;
          float: right;
          top: 20px;
          margin-top: 0 !important;
          z-index: 100;
        }
        .jb-nav-list-container {
            width: 220px !important;
            margin-top: 20px;
        }
        .markdown {
          margin-left: 260px; 
        }
    </style>
    <div class="jb-nav-list-container" data-spy="affix" data-offset-top="230">
        <ul class="jb-nav-list">
            <li><a href="#x1812010899">1 值 Value</a></li>
            <li><a href="#x97152884">2 指令 Directive</a></li>
            <li><a href="#x890125816">3 文本 Text</a></li>
            <li><a href="#x1221926399">4 注释 Comment</a></li>
            <li><a href="#x750650433">5 表达式 Expression</a></li>
            <li><a href="#x2038510066">6 默认的方法扩展 Methods</a></li>
            <li><a href="#x1154836530">7 默认的函数扩展 Functions</a></li>
            <li><a href="#x1937656097">8 默认的自定义标签 Tags</a></li>
            <li><a href="#x1968843044">9 和 Velocity 的比较</a></li>
        </ul>
    </div>

    <div class="markdown">

<!-- markdown body begin -->

    <p>这个是 <code>jetbrick-template</code> 模板语法参考手册。我们推荐的模板文件扩展名为 <code>.jetx</code>，嵌入式子模板的扩展名为 <code>.inc.jetx</code>。</p>
<h1><a name="x1812010899"></a><span>1 值 Value</span></h1>
<p>语法：</p> 
<ul> 
 <li><code>${expression}</code>：输出表达式的计算结果。</li> 
 <li><code>$!{expression}</code>：输出表达式的计算结果，并 escape 其中的 HTML 标签。</li> 
</ul>
<p>其中 <code>expression</code> 为任何合法的 Java 表达式，参考: <a href="#expression">表达式</a>。</p>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
${user.name}
${user.book.available()}
$!{user.description}
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>如果 <code>expression</code> 为 <code>null</code>，则不会输出任何东西，如果需要输出 <code>null</code>，可以使用如下的方法扩展：<code>${expression.asString()}</code>。</li> 
  <li>如果 <code>expression</code> 的返回类型为 <code>void</code>，那么也不会做任何输出动作。</li> 
 </ul> 
</blockquote>
<h1><a name="x97152884"></a><span>2 指令 Directive</span></h1>
<h2><a name="x1765529987"></a><span>2.1 变量类型声明 #define</span></h2>
<p>jetbrick-template 为了提高性能，采用了强类型来编译模板，所以需要为每一个用到的变量定义变量类型。如下：</p>
<p>语法：</p> 
<ul> 
 <li><code>#define(type name, ...)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#define(String name)
#define(UserInfo user, List<UserInfo> userlist)
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>在相同作用域下面，不允许重复定义变量类型，变量只在当前作用域有效。</li> 
  <li>对于没有定义变量类型，默认作用域为全局有效(Global)。</li> 
  <li>对于没有定义变量类型，那么优先从上下文表达式中进行类型推导, 否则默认类型为 <code>Object</code>。</li> 
 </ul> 
</blockquote>
<h2><a name="x31238794"></a><span>2.2 赋值语句 #set</span></h2>
<p>语法：</p> 
<ul> 
 <li><code>#set(type name = value, ...)</code></li> 
 <li><code>#set(name = value, ...)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#set(int num = 1+2*3)
#set(color1 = "#ff0000", color2 = "#00ff00")
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>在相同作用域下面，不允许重复定义变量类型，变量只在当前作用域有效。</li> 
  <li>影响当前模板，以及子模板的 <code>JetContext</code> 变量。</li> 
  <li>不影响父模板的 <code>JetContext</code> 变量。</li> 
 </ul> 
</blockquote>
<h2><a name="x31241181"></a><span>2.3 赋值语句 #put</span></h2>
<p>将变量内容保存到当前模板以及所有父模板的 <code>JetContext</code> 中，方便父子模板间进行变量传递。</p>
<p>语法：</p> 
<ul> 
 <li><code>#put(name, value)</code></li> 
 <li><code>#put(name1, value1, name2, value2, ...)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#put("num", 1 + 2 * 3)
#put("user", user, "name", "jetbrick")
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>可以传递多个 key-value 对</li> 
  <li>参数 <code>name</code> 必须是 <code>String</code> 类型</li> 
 </ul> 
</blockquote>
<h2><a name="x1615167792"></a><span>2.4 条件语句 #if, #elseif, #else</span></h2>
<p>如果 <code>#if</code> 条件表达式计算结果为 <code>true</code> 或非空，则输出指令所包含的块, 否则输出 <code>#else</code> 指令块。</p>
<p>语法：</p> 
<ul> 
 <li><code>#if(expression)</code> ... <code>#end</code></li> 
 <li><code>#if(expression)</code> ... <code>#else</code> ... <code>#end</code></li> 
 <li><code>#if(expression)</code> ... <code>#elseif(expression)</code> ... <code>#else</code> ... <code>#end</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#if (user.role == "admin")
	...
#elseif (user.role == "vip")
	...
#elseif (user.role == "guest")
	...
#else
	...
#end
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>对于 <code>expression</code> 为非 <code>Boolean</code> 值：非零数字，非空字串，非空集合，非 <code>null</code> 对象，即为 <code>true</code>。</li> 
  <li><code>#elseif</code> 允许出现多次。</li> 
  <li>如果 <code>#else</code> 后面紧跟着其他文本，比如 <code>#elseABC</code>，那么可以通过添加一对空括号来分割，修改成 <code>#else()ABC</code>。这样可读性就能加强，模板解析也不会出现问题。所有的无参数指令，比如 <code>#end</code>，<code>#break</code>，<code>#stop</code> 都支持这样操作。<code>()</code> 前面和之间请不要插入任何空格。</li> 
 </ul> 
</blockquote>
<h2><a name="x719310441"></a><span>2.5 循环语句 #for</span></h2>
<p>循环重复输出指令所包含的块，如果是空的集合对象，那么输出 <code>#else</code> 块。</p>
<p>语法：</p> 
<ul> 
 <li><code>#for(id: expression)</code> ... <code>#end</code></li> 
 <li><code>#for(id: expression)</code> ... <code>#else</code> ... <code>#end</code></li> 
 <li><code>#for(type id: expression)</code> ... <code>#end</code></li> 
 <li><code>#for(type id: expression)</code> ... <code>#else</code> ... <code>#end</code></li> 
</ul>
<p><code>#for</code> 支持以下类型的 <code>expression</code></p> 
<ul> 
 <li>Iterator</li> 
 <li>Iterable (Collection, ...)</li> 
 <li>Map</li> 
 <li>Enumeration</li> 
 <li>Array</li> 
 <li>null (空循环)</li> 
 <li>Object (只循环一次)</li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#for (book : user.books)
	${for.index} // 内部循环计数器，从 1 开始计数
	...
#end
]]></script>
<p>循环变量 id 类型声明，用作强制转型，避免类型推导失败。</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#for (Book book : user.books)
	...
#end
]]></script>
<p>指令 <code>#else</code> 可用于循环为空时的内容输出。</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#for (Book book : user.books)
	...
#else
	No books are found in here.
#end
]]></script>
<h3><a name="x1058087874"></a><span>2.5.1 for 内部对象</span></h3> 
<ul> 
 <li><code>for.index</code> 可用于内部循环计数，从 1 开始计数。</li> 
 <li><code>for.size</code> 获取循环总数。如果对 Iterator 进行循环，或者对非 Collection 的 Iterable 进行循环，则返回 -1。</li> 
 <li><code>for.first</code> 是否第一个元素。</li> 
 <li><code>for.last</code> 是否最后一个元素。</li> 
 <li><code>for.odd</code> 是否第奇数个元素。</li> 
 <li><code>for.even</code> 是否第偶数个元素。</li> 
</ul>
<h2><a name="x520315191"></a><span>2.6 循环中断或继续语句 #break, #continue</span></h2>
<p>当 <code>expression</code> 为 <code>true</code>，<code>#break</code> 中断当前循环，而 <code>#continue</code> 跳过余下的内容，跳到下一个循环。</p>
<p>语法：</p> 
<ul> 
 <li><code>#break</code></li> 
 <li><code>#break(expression)</code></li> 
 <li><code>#continue</code></li> 
 <li><code>#continue(expression)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#for (book : user.books)
	...
	#break(book.price > 100)
	...
#end
]]></script> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#for (book : user.books)
	...
	#continue(book.price > 100)
	...
#end
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>无参数格式代表 <code>expression</code> 永远为 <code>true</code>。</li> 
 </ul> 
</blockquote>
<h2><a name="x1448344112"></a><span>2.7 停止解析语句 #stop</span></h2>
<p>当 <code>expression</code> 为真或非空时，停止模板运行。</p>
<p>语法：</p> 
<ul> 
 <li><code>#stop</code></li> 
 <li><code>#stop(expression)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#stop(error != null)
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>无参数格式代表 <code>expression</code> 永远为 <code>true</code>。</li> 
 </ul> 
</blockquote>
<h2><a name="x347886788"></a><span>2.8 嵌套模板语句 #include</span></h2>
<p>嵌入一个子模板，将子模板内容输出到当前位置。</p>
<p>语法：</p> 
<ul> 
 <li><code>#include(file)</code></li> 
 <li><code>#include(file, parameters)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#include("/include/header.jetx") // 绝对路径
#include("../userinfo.jetx") // 相对路径
#include(file) // 动态路径
#include("/include/header.jetx", {role: "admin"}) // 传递参数
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>子模板自动共享父模板 <code>JetContext</code> 变量，同时还可以另外传递一些参数给子模板。</li> 
  <li>子模板可以用 <code>#put</code> 指令修改父模板的 <code>JetContext</code>，然后在父模板中用 <code>context[&quot;name&quot;]</code> 获取变量值。</li> 
 </ul> 
</blockquote>
<p>具体用法请查考： <a href="faq-include.html">在 jetbrick-template 中如何使用 #include？</a></p>
<h2><a name="x778876459"></a><span>2.9 宏定义 #macro</span></h2>
<p>定义一个代码片段，然后可以重复使用。(New from 1.1.0)</p>
<p>语法：</p> 
<ul> 
 <li><code>#macro name(type name, ...)</code> ... <code>#end</code></li> 
</ul> 
<blockquote>
 <p><strong>注意</strong>： 每个宏可以定义 0~N 个参数。</p> 
</blockquote>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#macro header(String name)
    Hello ${name}!
#end

${header("张三")}
${header("李四")}
]]></script>
<p>输出结果：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
    Hello 张三!
    Hello 李四!
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>宏的调用就和函数调用一样。(如果和函数存在名称冲突，那么宏定义优先)</li> 
  <li>宏的调用返回值是 Void，所以不支持对返回值进行计算。</li> 
 </ul> 
</blockquote>
<h2><a name="x1007843513"></a><span>2.10 自定义标签 #tag</span></h2>
<p>jetbrick-template 支持自定义 Tag，类似于 JSP Taglib，但是要比 JSP Taglib 更简单更好用。(New from 1.1.0)</p>
<p>语法：</p> 
<ul> 
 <li><code>#tag name(args ...)</code> ... <code>#end</code></li> 
</ul> 
<blockquote>
 <p><strong>注意</strong>： </p> 
 <ul> 
  <li>需要在 Java 端先定义 Tag 标签的实现。</li> 
  <li>Tag 调用的参数必须和定义的一致。</li> 
 </ul> 
</blockquote>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#tag layout("layout.jetx")
    Hello ${name}!
#end
]]></script>
<p>具体用法请查考： <a href="faq-tag.html">在 jetbrick-template 中如何自定义 Tag？</a></p>
<h1><a name="x890125816"></a><span>3 文本 Text</span></h1>
<p>普通文本内容将会被直接进行输出。</p>
<h2><a name="x136317352"></a><span>3.1 不解析文本块</span></h2>
<p>原样输出模板内容，用于输出纯文本内容，或批量转义块中的特殊字符。类似于 XML 中的 CDATA。</p>
<p>语法：</p> 
<ul> 
 <li><code>#[[</code> ... <code>]]#</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#[[
	Source code will be displayed in here.
	Hello ${user.name}	
]]#
]]></script>
<h2><a name="x1841434365"></a><span>3.2 特殊字符转义</span></h2>
<p>原样输出指令特殊字符，转义字符由 <code>\</code> 进行转义。</p>
<p>语法：</p> 
<ul> 
 <li><code>\\</code></li> 
 <li><code>\#</code></li> 
 <li><code>\$</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
\#if
\${user.name}
\\${user.name}
]]></script> 
<blockquote>
 <p><strong>注意</strong>：</p> 
 <ul> 
  <li>如果遇到类似 <code>#ff0000</code> 类似于指令的内容，但又不是系统定义的指令，那么也会原样输出，并不需要进行转义。</li> 
  <li><code>\</code> 后面跟的字符不是 <code>#</code> 和 <code>$</code>，也不需要进行转义，直接输出。</li> 
 </ul> 
</blockquote>
<h1><a name="x1221926399"></a><span>4 注释 Comment</span></h1>
<h2><a name="x34432814"></a><span>4.1 行注释</span></h2>
<p>隐藏行注释的内容，以换行符结束，用于注解过程，或屏蔽指令内容。</p>
<p>语法：</p> 
<ul> 
 <li><code>##</code> ...</li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
${user.name} ## This is a line comment.
]]></script>
<h2><a name="x22388601"></a><span>4.2 块注释</span></h2>
<p>隐藏块注释内容，可包含换行符，用于注解过程，或屏蔽指令内容。</p>
<p>语法：</p> 
<ul> 
 <li><code>#--</code> ... <code>--#</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#--
	This is a block comment.
--#
]]></script>
<p><a name="expression"></a></p>
<h1><a name="x750650433"></a><span>5 表达式 Expression</span></h1>
<p>支持所有 Java 表达式，并对其进行了一些有用的扩展。</p>
<h3><a name="x82363453"></a><span>5.0.1 与 Java 相同的地方 (运算符优先级和 Java 保存一致)</span></h3> 
<ul> 
 <li>数字常量： <code>123</code> <code>123L</code> <code>0.01D</code> <code>99.99E-10D</code></li> 
 <li>字符串常量： <code>&quot;abc\r\n&quot;</code> <code>'abc\u00A0\r\n'</code></li> 
 <li>BOOLEAN 常量：<code>true</code> <code>false</code></li> 
 <li>NULL 常量: <code>null</code></li> 
 <li>算术运行： <code>+</code> <code>-</code> <code>*</code> <code>/</code> <code>%</code></li> 
 <li>自增/自减： <code>++</code> <code>--</code></li> 
 <li>位运算： <code>~</code> <code>&amp;</code> <code>|</code></li> 
 <li>移位运算： <code>&gt;&gt;</code> <code>&gt;&gt;&gt;</code> <code>&lt;&lt;</code></li> 
 <li>比较运算： <code>==</code> <code>!=</code> <code>&gt;</code> <code>&gt;=</code> <code>&lt;</code> <code>&lt;=</code></li> 
 <li>逻辑运算： <code>!</code> <code>&amp;&amp;</code> <code>||</code></li> 
 <li>三元表达式： <code>? :</code></li> 
 <li>实例对象判断： <code>instanceof</code></li> 
 <li>NEW 对象：<code>new Object(...)</code></li> 
 <li>强制类型转换：<code>(java.lang.String)obj</code></li> 
 <li>数组存取：<code>array[i]</code></li> 
 <li>字段访问：<code>obj.field</code></li> 
 <li>方法调用：<code>obj.method(...)</code></li> 
 <li>方法调用：支持可变参数方法(Varargs)和重载方法(Overload)</li> 
 <li>静态字段调用：<code>@Long.MAX_VALUE</code></li> 
 <li>静态方法调用：<code>@Long.valueOf(&quot;123&quot;)</code></li> 
 <li>支持数组定义：<code>String[]</code></li> 
 <li>支持泛型定义：<code>List&lt;String&gt;</code> <code>Map&lt;String[], List&lt;?&gt;&gt;</code></li> 
</ul>
<h3><a name="x1957148670"></a><span>5.0.2 与 Java 不同的地方</span></h3> 
<ul> 
 <li>双等号 <code>==</code> 会被解析成 <code>equals()</code> 方法比较，而不是比内存地址。</li> 
 <li>单双引号都将生成字符串：<code>'a'</code> 或 <code>&quot;a&quot;</code> 都是<code>String</code> 类型。</li> 
 <li>Bean 属性会解析成 getter 方法调用，<code>${user.name}</code> 等价于 <code>${user.getName()}</code></li> 
 <li>所有实现 <code>Comparable</code> 的对象都支持比较运算符，比如：<code>#if(date1 &lt; date2)</code>，可以比较日期的先后。</li> 
 <li>所有对象都条件测试，并返回 <code>true</code> 或者 <code>false</code>。对于非 <code>Boolean</code> 对象，所有非零数字，非空字串，非空集合，非 <code>null</code> 对象，即为 <code>true</code>。</li> 
 <li><code>List</code> 和 <code>Map</code> 可以方括号取值，比如：<code>list[0]</code> 等价于 <code>list.get(0)</code>，<code>map[&quot;abc&quot;]</code> 等价于 <code>map.get(&quot;abc&quot;)</code>。</li> 
 <li><code>Map</code> 和 <code>JetContext</code> 对象支持 <code>.</code> 访问内部的对象（属性调用），如： <code>map.key</code>, <code>context.key</code>。</li> 
 <li>支持 Groovy 的 <code>?.</code> 安全调用，以避免 <code>NullPointerException</code>。</li> 
 <li>静态字段/方法调用，需要用 <code>@</code> 前缀，比如： <code>@Long.MAX_VALUE</code>，如果类带包名，需要这么用： <code>@(java.lang.Long).valueOf(&quot;123&quot;)</code></li> 
</ul>
<h2><a name="x948751994"></a><span>5.1 变量名 Variable</span></h2>
<p>可以是任意合法的 Java 变量名：</p> 
<ul> 
 <li>其中 <code>$</code> 开头的变量为模板内部变量，不允许直接使用。</li> 
 <li>不允许使用 Java 关键字。</li> 
</ul>
<p>如：<code>user</code>, <code>user_name</code>, <code>userName</code></p>
<p>2 个内置的特殊变量：</p> 
<ul> 
 <li><code>context</code>： 当前模板的 <code>JetContext</code> 对象。</li> 
 <li><code>for</code>： 用于 <code>#for</code> 指令内部状态对象。具体参考 <code>#for</code> 指令用法。</li> 
</ul>
<h2><a name="x1847340345"></a><span>5.2 List 常量</span></h2>
<p>语法：</p> 
<ul> 
 <li><code>[item, ...]</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
[] // empty List
[1, 2, 3, 4, 5]
["abc", 123, new Date(), 1+2*3]
]]></script>
<p>取值：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
${list[index]}
${list.get(index)}

// 安全调用
${list?[index]}
${list?.get(index)}
]]></script>
<h2><a name="x1996788741"></a><span>5.3 Map 常量</span></h2>
<p>语法：</p> 
<ul> 
 <li><code>{key: value, ...}</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
{} // empty Map
{"name" : "Jason", "statue" : 0}
]]></script>
<p>取值：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
${map.key}
${map["key"]}
${map.get("key")}

// 安全调用
${map?.key}
${map?["key"]}
${map?.get("key")}
]]></script>
<h2><a name="x394735919"></a><span>5.4 Bean 属性调用 bean.property</span></h2>
<p>Bean 属性会解析成 getter 方法调用。</p>
<p>属性查找顺序，以 <code>${obj.foo}</code> 为例：</p> 
<ol> 
 <li>查找 obj.getFoo() 方法</li> 
 <li>查找 obj.isFoo() 方法</li> 
 <li>查找 obj class 的 foo 字段</li> 
 <li>查找 obj.get(name) 方法 (如果是 <code>Map</code> 或者 <code>JetContext</code>)</li> 
</ol>
<p>以上查找过程会在第一次编译的时候完成，不影响性能。<br />支持对属性返回值的类型推导。</p> 
<blockquote>
 <p><strong>注意</strong>： <code>jetbrick-template</code> 支持属性的安全调用，和 Groovy 相同，你可以使用 <code>?.</code> 来代替 <code>.</code>，以避免出现 <code>NullPointerException</code>。</p> 
</blockquote>
<h2><a name="x1481011027"></a><span>5.5 Bean 方法调用 bean.method(...)</span></h2> 
<ul> 
 <li>支持普通方法调用</li> 
 <li>支持不定长参数方法调用 Varargs</li> 
 <li>支持方法重载 Overload</li> 
 <li>支持扩展方法调用。参考：<a href="userguide.html#methods">扩展方法调用</a></li> 
 <li>支持对方法返回值的类型推导</li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
## 方法重载 Overload
${"Hello".substring(2)}
${"Hello".substring(2, 3)}
]]></script> 
<blockquote>
 <p><strong>注意</strong>： <code>jetbrick-template</code> 支持方法的安全调用，和 Groovy 相同，你可以使用 <code>?.</code> 来代替 <code>.</code>，以避免出现 <code>NullPointerException</code>。</p> 
</blockquote>
<h2><a name="x134013728"></a><span>5.6 函数调用 function</span></h2>
<p>jetbrick-template 还支持函数调用，如 <code>${now()}</code>, <code>${include(&quot;tag.jetx&quot;)}</code>。</p>
<p>具体参考：<a href="userguide.html#functions">扩展函数调用</a></p>
<h2><a name="x502090105"></a><span>5.7 静态字段调用 @Class.Field</span></h2>
<p>(New from 1.1.0)</p>
<p>语法：</p> 
<ul> 
 <li><code>@Class.Field</code></li> 
 <li><code>@(package.Class).Field</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
${@Long.MAX_VALUE}
${@(java.lang.Long).MAX_VALUE}
]]></script>
<h2><a name="x1814113504"></a><span>5.8 静态方法调用 @Class.method</span></h2>
<p>(New from 1.1.0)</p>
<p>语法：</p> 
<ul> 
 <li><code>@Class.method(...)</code></li> 
 <li><code>@(package.Class).method(...)</code></li> 
</ul>
<p>示例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
${@Collections.emptyList()}
${@(java.lang.Long).valueOf("123")}
]]></script>
<p><a name="default_methods"></a></p>
<h1><a name="x2038510066"></a><span>6 默认的方法扩展 Methods</span></h1>
<p>所有方法扩展定义在 <code>jetbrick.template.runtime.JetMethods</code></p>
<h2><a name="x781953175"></a><span>6.1 基本数据类型转换 Cast</span></h2> 
<ul> 
 <li>String.asBoolean()</li> 
 <li>String.asChar()</li> 
 <li>String.asByte()</li> 
 <li>String.asShort()</li> 
 <li>String.asInt()</li> 
 <li>String.asLong()</li> 
 <li>String.asFloat()</li> 
 <li>String.asDouble()</li> 
 <li>String.asDate()</li> 
 <li>String.asDate(String format)</li> 
 <li>Object.asString()</li> 
</ul>
<h2><a name="x1169187945"></a><span>6.2 集合类型转换 Cast</span></h2> 
<ul> 
 <li>Collection.asList()</li> 
 <li>boolean[].asList()</li> 
 <li>char[].asList()</li> 
 <li>byte[].asList()</li> 
 <li>short[].asList()</li> 
 <li>int[].asList()</li> 
 <li>long[].asList()</li> 
 <li>float[].asList()</li> 
 <li>doubl[].asList()</li> 
 <li>Object[].asList()</li> 
</ul>
<h2><a name="x355317298"></a><span>6.3 数据格式化 Format</span></h2> 
<ul> 
 <li>Number.format()</li> 
 <li>Number.format(String format)</li> 
 <li>Date.format()</li> 
 <li>Date.format(String format)</li> 
</ul>
<h2><a name="x1727847930"></a><span>6.4 数据 Escape/Unescape</span></h2> 
<ul> 
 <li>String.escapeJava()</li> 
 <li>String.unescapeJava()</li> 
 <li>String.escapeJavaScript()</li> 
 <li>String.unescapeJavaScript()</li> 
 <li>String.escapeXml()</li> 
 <li>String.unescapeXml()</li> 
 <li>String.escapeUrl()</li> 
 <li>String.escapeUrl(String encoding)</li> 
 <li>String.unescapeUrl()</li> 
 <li>String.unescapeUrl(String encoding)</li> 
</ul>
<h2><a name="x14779721"></a><span>6.5 默认值输出</span></h2> 
<ul> 
 <li>Object.asDefault(Object defaultValue)</li> 
</ul>
<h2><a name="x591511809"></a><span>6.6 JSON 输出</span></h2> 
<ul> 
 <li>Object.asJSON()</li> 
</ul>
<h2><a name="x1079447065"></a><span>6.7 字符串转换</span></h2> 
<ul> 
 <li>String.toUnderlineName()</li> 
 <li>String.toCamelCase()</li> 
 <li>String.toCapitalizeCamelCase()</li> 
 <li>String.repeat(int count)</li> 
</ul>
<h2><a name="x969081998"></a><span>6.8 算术计算</span></h2> 
<ul> 
 <li>int[].sum()</li> 
 <li>int[].avg()</li> 
 <li>int[].max()</li> 
 <li>int[].min()</li> 
</ul>
<p><a name="default_functions"></a></p>
<h1><a name="x1154836530"></a><span>7 默认的函数扩展 Functions</span></h1>
<p>所有函数扩展定义在 <code>jetbrick.template.runtime.JetFunctions</code></p>
<h2><a name="x748057859"></a><span>7.1 常用函数</span></h2> 
<ul> 
 <li><p><code>Date now()</code><br /> 获取当前时间</p></li> 
 <li><p><code>int random()</code><br /> 获取一个随机数</p></li> 
 <li><p><code>UUID uuid()</code><br /> 获取一个 UUID</p></li> 
</ul>
<h2><a name="x665841341"></a><span>7.2 循环计数生成器</span></h2>
<p>生成一个用于循环的数组，主要用于 <code>#for</code> 的循环迭代。</p>
<p>@Deprecated from 1.0.2</p> 
<ul> 
 <li><code>int[] range(int start, int stop)</code></li> 
 <li><code>int[] range(int start, int stop, int step)</code></li> 
</ul>
<p>New added from 1.0.2</p> 
<ul> 
 <li><code>Iterator&lt;Integer&gt; iterator(int start, int stop)</code></li> 
 <li><code>Iterator&lt;Integer&gt; iterator(int start, int stop, int step)</code></li> 
</ul>
<p>范例：</p> 
<script type="syntaxhighlighter" class="brush: text"><![CDATA[
#for (int i : iterator(1,100))
	${i}
#end
]]></script>
<h2><a name="x958665306"></a><span>7.3 嵌入子模板 include(...)</span></h2>
<p>嵌入一个子模板。和 <code>#include</code> 指令的区别，此函数对子模板的输出进行了缓存，可以处理返回的内容，但是效率没有 <code>#include</code> 指令高。</p> 
<ul> 
 <li><code>String include(String relativeName)</code></li> 
 <li><code>String include(String relativeName, Map&lt;String, Object&gt; parameters)</code></li> 
</ul>
<h2><a name="x1231948809"></a><span>7.4 嵌入纯文本文件 read(...)</span></h2> 
<ul> 
 <li><code>String read(String relativeName)</code></li> 
 <li><code>String read(String relativeName, String encoding)</code></li> 
</ul>
<h2><a name="x1292645738"></a><span>7.5 调试专用函数 debug(...)</span></h2> 
<ul> 
 <li><code>void debug(String format, Object... args)</code><br /> 输出调试信息，需要配合 Slf4j 使用。 参数格式请查看 <a href="http://www.slf4j.org/apidocs/org/slf4j/Logger.html">Slf4j Logger</a>。</li> 
</ul>
<h2><a name="x117672627"></a><span>7.6 Web 路径获取 ctxpath() / webroot()</span></h2> 
<ul> 
 <li><p><code>String ctxpath()</code><br /> 返回相对于 web 根目录的绝对路径，如 /myapp</p></li> 
 <li><p><code>String ctxpath(String url)</code><br /> 将 url 转换为相对于 web 根目录的绝对路径，如 /myapp/path/file</p></li> 
 <li><p><code>String webroot()</code><br /> 返回完整的 web 站点路径，如 <a href="http://127.0.0.1:8080/myapp">http://127.0.0.1:8080/myapp</a></p></li> 
 <li><p><code>String webroot(String url)</code><br /> 将 url 转换为完整的 web 站点路径，如 <a href="http://127.0.0.1:8080/myapp/path/file">http://127.0.0.1:8080/myapp/path/file</a></p></li> 
</ul>
<p><a name="default_tags"></a></p>
<h1><a name="x1937656097"></a><span>8 默认的自定义标签 Tags</span></h1>
<p>所有 Tags 定义在 <code>jetbrick.template.runtime.JetTags</code></p> 
<ul> 
 <li><p><code>#tag layout(String file)</code> ... <code>#end</code><br /> 应用页面布局。<br /> 参考：<a href="faq-layout.html">jetbrick-template 中如何实现 layout 功能？</a></p></li> 
 <li><p><code>#tag layout(String file, Map&lt;String, Object&gt; parameters)</code> ... <code>#end</code><br /> 应用页面布局(支持传递传输)。<br /> 参考：<a href="faq-layout.html">jetbrick-template 中如何实现 layout 功能？</a></p></li> 
 <li><p><code>#tag block(String name)</code> ... <code>#end</code><br /> 将块内容保存到变量名为 name 的 JetContext 中。<br /> 参考：<a href="faq-layout.html">jetbrick-template 中如何实现 layout 功能？</a></p></li> 
 <li><p><code>#tag default_block(String name)</code> ... <code>#end</code><br /> 如果不存在指定的 JetContext 变量，那么输出 default_block 块内容，否则输出指定的 JetContext 变量。<br /> 参考：<a href="faq-layout.html">jetbrick-template 中如何实现 layout 功能？</a></p></li> 
 <li><p><code>#tag application_cache(String name, long timeout)</code> ... <code>#end</code><br /> 将内存缓存到 ServletContext 中，在 timeout 秒之后自动超时。</p></li> 
 <li><p><code>#tag session_cache(String name, long timeout)</code> ... <code>#end</code><br /> 将内存缓存到 HttpSession 中，在 timeout 秒之后自动超时。</p></li> 
</ul>
<p><a name="velocity"></a></p>
<h1><a name="x1968843044"></a><span>9 和 Velocity 的比较</span></h1>
<h2><a name="x1094687580"></a><span>9.1 语法差异</span></h2> 
<ul> 
 <li>jetbrick-template 指令中的变量不加 <code>$</code> 符，只支持 <code>#if(x == y)</code>，不支持 <code>#if($x == $y)</code>，因为指令中没有加引号的字符串就是变量，和常规语言的语法一样，加$有点废话，而且容易忘写。</li> 
 <li>jetbrick-template 占位符必需加大括号，只支持 <code>${foo}</code>，不支持 <code>$foo</code>，因为 <code>$</code> 在 JavaScript 中也是合法变量名符号，而 <code>${}</code> 不是，减少混淆，也防止多人开发时，有人加大括号，有人不加，干脆没得选，都加，保持一致。</li> 
 <li>jetbrick-template 占位符当变量为 <code>null</code> 时输出空白串，而不像 Velocity 那样原样输出指令原文，即 <code>${foo}</code>，等价于 Velocity 的 <code>$!{foo}</code>，以免开发人员忘写感叹号，泄漏表达式源码，如需原样输出，可使用转义 <code>\${foo}</code>， 在 jetbrick-template 中，<code>$!{foo}</code> 表示对内容进行 HTML 过滤，用于原样输出 HTML 片段。</li> 
 <li>jetbrick-template 支持在所有使用变量的地方，进行表达式计算，也就是你不需要像 Velocity 那样，先 <code>#set($j = $i + 1)</code> 到一个临时变量，再输出临时变量 <code>${j}</code>，jetbrick-template 可以直接输出 <code>${i + 1}</code>，其它指令也一样，比如：<code>#if(i + 1 == n)</code>。</li> 
 <li>jetbrick-template 采用扩展 Class 原生方法的方式，如：<code>${&quot;str&quot;.toChar()}</code>，而不像 Velocity 的 Tool 工具方法那样：<code>$(StringTool.toChar(&quot;a&quot;))</code>，这样的调用方式更直观，更符合代码书写习惯。</li> 
 <li>jetbrick-template 支持属性和方法的安全调用。如 <code>${user?.name}</code>，<code>${user?.hasRole(&quot;vip&quot;)}</code>。如果 <code>user</code> 对象为 <code>null</code>，那么返回结果就是 <code>null</code>，不会出现烦人的 <code>NullPointerException</code>。</li> 
 <li>jetbrick-template 还支持静态字段/方法调用，函数扩展，上下文相关的方法/函数扩展。</li> 
</ul>
<h2><a name="x775409745"></a><span>9.2 指令差异</span></h2>

    <table>
    <tr>
        <th width="140px">velocity</th>
        <th width="140px">jetbrick-template</th>
        <th width="40px">异同</th>
        <th width="100px">功能</th>
        <th>变化</th>
    </tr>
    <tr>
        <td>${foo.bar}<br>$foo.bar</td>
        <td>${foo.bar}</td>
        <td><font color="green">相同</font></td>
        <td>输出占位符</td>
        <td>jetbrick-template 大括号必需</td>
    </tr>
    <tr>
        <td>$!{foo.bar}<br>$!foo.bar</td>
        <td>$!{foo.bar}</td>
        <td><font color="red">不同</font></td>
        <td>空值不显示源码</td>
        <td>velocity 为空值不显示源码<br>jetbrick-template 改为HTML过滤输出</td>
    </tr>
    <tr>
        <td>## ...<br>#* ... *#</td>
        <td>## ...<br>#-- ... --#</td>
        <td>相似</td>
        <td>注释</td>
        <td>块注释格式不一样</td>
    </tr>
    <tr>
        <td>#[[ ... ]]#</td>
        <td>#[[ ... ]]#</td>
        <td><font color="green">相同</font></td>
        <td>不解析文本块</td>
        <td></td>
    </tr>
    <tr>
        <td>\# \$ \\</td>
        <td>\# \$ \\</td>
        <td><font color="green">相同</font></td>
        <td>特殊字符转义</td>
        <td></td>
    </tr>
    <tr>
        <td>n/a</td>
        <td>#define(Type foo = bar)</td>
        <td><font color="red">新增</font></td>
        <td>给变量声明类型</td>
        <td></td>
    </tr>
    <tr>
        <td>#set($foo = $bar)</td>
        <td>#set(foo = bar)<br>#set(Type foo = bar)</td>
        <td><font color="green">相同</font></td>
        <td>给变量赋值</td>
        <td>可带类型声明</td>
    </tr>
    <tr>
        <td>n/a</td>
        <td>#put(name, value)</td>
        <td><font color="red">新增</font></td>
        <td>保存变量到全局</td>
        <td>支持父子模板参数的全局传递</td>
    </tr>
    <tr>
        <td>#if($foo == $bar)</td>
        <td>#if(foo == bar)</td>
        <td><font color="green">相同</font></td>
        <td>条件判断</td>
        <td></td>
    </tr>
    <tr>
        <td>#elseif($foo == $bar)</td>
        <td>#elseif(foo == bar)</td>
        <td><font color="green">相同</font></td>
        <td>否定条件判断</td>
        <td></td>
    </tr>
    <tr>
        <td>#else</td>
        <td>#else</td>
        <td><font color="green">相同</font></td>
        <td>否定判断</td>
        <td></td>
    </tr>
    <tr>
        <td>#end</td>
        <td>#end</td>
        <td><font color="green">相同</font></td>
        <td>结束指令</td>
        <td></td>
    </tr>
    <tr>
        <td>#foreach($item in $list)</td>
        <td>#for(item : list)<br>#for(Type item : list)</td>
        <td>相似</td>
        <td>循环指令</td>
        <td>改为Java格式，可以带类型声明</td>
    </tr>
    <tr>
        <td>#break</td>
        <td>#break<br>#break(foo == bar)</td>
        <td><font color="green">相同</font></td>
        <td>中断循环</td>
        <td>可以直接带条件</td>
    </tr>
    <tr>
        <td>n/a</td>
        <td>#continue<br>#continue(foo == bar)</td>
        <td><font color="red">新增</font></td>
        <td>继续下一个循环</td>
        <td>可以直接带条件</td>
    </tr>
    <tr>
        <td>#stop</td>
        <td>#stop<br>#stop(foo == bar)</td>
        <td><font color="green">相同</font></td>
        <td>停止模板解析</td>
        <td>可以直接带条件</td>
    </tr>
    <tr>
        <td>#macro($foo)</td>
        <td>#macro foo(...)</td>
        <td>相似</td>
        <td>可复用模板片段宏</td>
        <td>velocity 将宏作为指令执行<br> jetbrick-template 作为函数执行</td>
    </tr>
    <tr>
        <td>n/a</td>
        <td>#tag foo(...)</td>
        <td><font color="red">新增</font></td>
        <td>自定义标签</td>
        <td>jetbrick-template 允许自定义标签</td>
    </tr>
    <tr>
        <td>#include("foo.txt")</td>
        <td>read("foo.txt")</td>
        <td>相似</td>
        <td>读取文本文件内容</td>
        <td>jetbrick-template 用扩展函数实现</td>
    </tr>
    <tr>
        <td>#parse("foo.vm")</td>
        <td>#include("foo.jetx")<br/>#include("foo.jetx", args)</td>
        <td><font color="green">相同</font></td>
        <td>包含另一模板输出</td>
        <td>jetbrick-template 支持私有参数传递</td>
    </tr>
    <tr>
        <td>#evaluate("${1 + 2}")</td>
        <td>n/a</td>
        <td><font color="red">不同</font></td>
        <td>模板求值</td>
        <td>jetbrick-tempate 暂不支持</td>
    </tr>
</table>
<!-- markdown body end -->

    </div>
</div>

<div class="container">
    <div class="jb-footer">
        Copyright 2010-2014 Guoqiang Chen. All rights reserved.
        <br/>subchen&#64;gmail.com, QQ 交流圈：310491655
    </div>
</div>

<style type="text/css">
#cnzz_stat_icon_1000210720 {
	display: none;
}
</style>
<script type="text/javascript">
var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
document.write(unescape("%3Cspan id='cnzz_stat_icon_1000210720'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s22.cnzz.com/z_stat.php%3Fid%3D1000210720' type='text/javascript'%3E%3C/script%3E"));
</script>



</body>
</html>
